<template>
    <div ref="selectRef" :class="['pe-select', `pe-select-${size}`, disabled ? 'pe-select-disabled' : '']"
        @click.stop="onClick" @mouseenter="clearShowFlag = true" @mouseleave="clearShowFlag = false">
        <div v-if="useSlots().prefix" class="pe-select-prefix">
            <slot name="prefix"></slot>
        </div>
        <div class="pe-select-inner">
            <input ref="inputRef" type="text" class="pe-select-input" @focus="onFocus" :disabled="disabled" />
            <template v-if="getShow()">
                <div v-if="!multiple" class="pe-select-show">{{ showValue }}</div>
                <template v-else>
                    <slot name="tag">
                        <div v-if="!collapseTags" class="pe-select-multiple">
                            <Tag v-for="(item, index) in showValue" size="small" closable @close="onClose(index)">{{
                                item }}
                            </Tag>
                        </div>
                        <div v-else class="pe-select-multiple">
                            <Tag size="small"
                                v-for="item in ((showValue as Array<string | number>).length > maxCollapseTags ? maxCollapseTags : (showValue as Array<string | number>).length)"
                                closable @close="onClose(item - 1)">{{ (showValue as Array<string | number>)[item - 1]
                                    }}
                            </Tag>
                            <Tag v-if="maxCollapseTags >= 1 && (showValue as Array<string | number>).length > maxCollapseTags"
                                ref="tagRef" size="small" @mouseenter="show1 = true" @mouseleave="show1 = false">+{{
                                    (showValue as Array<string | number>).length - maxCollapseTags
                                }}</Tag>
                            <Popup v-model="show1" ref="popupRef1">
                                <div style="padding: 0 10px;">
                                    <Tag
                                        v-for="item in (showValue as Array<string | number>).filter((_item, index) => index >= maxCollapseTags)">
                                        {{ item }}</Tag>
                                </div>
                            </Popup>
                        </div>
                    </slot>
                </template>
            </template>
            <span v-else>{{ placeholder }}</span>
        </div>
        <div v-if="getShow() && clearShowFlag && clearable" class="pe-select-clear" @click.stop="onClear"
            @mouseenter="closeShow = false" @mouseleave="closeShow = true">
            <Close v-if="closeShow" />
            <Circleclosefilled v-else />
        </div>
        <ArrowDown v-else :style="{ transform: rotateFlag ? 'rotate(180deg)' : 'rotate(0)' }" />
        <Popup v-model="show" ref="popupRef" :domFlag="false">
            <div v-if="useSlots().header" class="pe-select-header">
                <slot name="header"></slot>
            </div>
            <ScrollBar maxHeight="200px" :style="{ minWidth: width }">
                <slot></slot>
            </ScrollBar>
            <div v-if="useSlots().footer" class="pe-select-footer">
                <slot name="footer"></slot>
            </div>
        </Popup>
    </div>
</template>

<script setup lang="ts">
import { nextTick, provide, ref, watch, useSlots, toRefs } from 'vue';
import ScrollBar from "../scrollbar/scrollbar.vue";
import Popup from "../popup/popup.vue";
import ArrowDown from '../../icons/arrowdown.vue';
import Close from '../../icons/close.vue';
import Circleclosefilled from '../../icons/circleclosefilled.vue';
import Tag from '../tag/tag.vue';

const modelValue = defineModel<string | number | Array<string | number>>({ default: "" })
const showValue = ref<string | number | Array<string | number>>("")
const show = ref<boolean>(false)
const show1 = ref<boolean>(false)

const selectRef = ref<HTMLDivElement>()
const popupRef = ref<any>()

const tagRef = ref<any>()
const popupRef1 = ref<any>()

const closeShow = ref<boolean>(true)

/**
 * @param multiple 是否多选
 * @param disabled 是否禁用
 * @param size 输入框尺寸
 * @param clearable 是否可以清空选项
 * @param placeholder 占位符，默认为“Select”
 * @param collapse-tags 多选时是否将选中值按文字的形式展示
 * @param collapse-tags-tooltip 当鼠标悬停于折叠标签的文本时，是否显示所有选中的标签。 要使用此属性，collapse-tags属性必须设定为 true
 * @param max-collapse-tags 需要显示的 Tag 的最大数量 只有当 collapse-tags 设置为 true 时才会生效。
 */
interface Props {
    multiple?: boolean,
    disabled?: boolean,
    size?: 'default' | 'small' | 'large',
    clearable?: boolean,
    placeholder?: string,
    collapseTags?: boolean,
    collapseTagsTooltip?: boolean,
    maxCollapseTags?: number
}

const props = withDefaults(defineProps<Props>(), {
    multiple: false,
    disabled: false,
    size: 'default',
    clearable: false,
    placeholder: "Select",
    collapseTags: false,
    collapseTagsTooltip: false,
    maxCollapseTags: 1
})

/**
 * change 选中值发生变化时触发
 * visible-change 下拉框出现/隐藏时触发
 * remove-tag 多选模式下移除tag时触发
 * clear 用户点击清空按钮时触发
 */
const emits = defineEmits(["change", "visible-change", "remove-tag", "clear"])

const width = ref<string>("")

watch([props, modelValue], ([newProps]) => {
    nextTick(() => {
        popupRef.value?.setRef(selectRef.value)
        width.value = selectRef.value?.offsetWidth + "px"
        if (newProps.maxCollapseTags >= 1 && (showValue.value as Array<string | number>).length > newProps.maxCollapseTags) {
            popupRef1.value?.setRef(tagRef.value)
        }
    })
}, { immediate: true })

// 输入框元素
const inputRef = ref<HTMLInputElement>()
// 图标旋转
const rotateFlag = ref<boolean>(false)
// 清空图标显示
const clearShowFlag = ref<boolean>(false)

const onClear = () => {
    modelValue.value = props.multiple ? [] : ""
    emits("clear")
}

// 检查是否聚焦输入框
let flag = true
const onClick = () => {
    if (!props.disabled) {
        if (flag) {
            inputRef.value?.focus()
        } else {
            show.value = false
        }
        flag = !flag
    }
}

watch(show, newShow => {
    rotateFlag.value = newShow
    if (!newShow) {
        flag = true
    }
    emits("visible-change", newShow)
})

const onFocus = () => {
    show.value = true
}

const onChange = (val: string | number | Array<string | number>) => {
    emits("change", val)
    if (!props.multiple) {
        show.value = false
    }
}

const onClose = (index: number) => {
    let valueArr: Array<string | number> = JSON.parse(JSON.stringify(modelValue.value))
    let labelArr: Array<string | number> = JSON.parse(JSON.stringify(showValue.value))
    valueArr = valueArr.filter((_item, idx) => index !== idx)
    labelArr = labelArr.filter((_item, idx) => index !== idx)
    modelValue.value = valueArr
    showValue.value = labelArr
    emits("change", valueArr)
    emits("remove-tag", valueArr)
}

const getShow = () => {
    if (props.multiple) {
        return modelValue.value instanceof Array && modelValue.value.length > 0
    } else {
        return modelValue.value || modelValue.value === 0
    }
}

const { multiple } = toRefs(props)

provide("pe-select-value", modelValue)
provide("pe-select-multiple", multiple)
provide("pe-select-change", onChange)
provide("pe-select-showValue", showValue)
</script>

<script lang="ts">
export default {
    name: "pe-select"
}
</script>
